package com.kakarote.examine.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.kakarote.core.common.cache.CrmCacheKey;
import com.kakarote.core.common.enums.SystemCodeEnum;
import com.kakarote.core.entity.UserInfo;
import com.kakarote.core.exception.CrmException;
import com.kakarote.core.feign.admin.entity.AdminMessageBO;
import com.kakarote.core.feign.admin.entity.AdminMessageEnum;
import com.kakarote.core.feign.admin.entity.SimpleUser;
import com.kakarote.core.feign.admin.service.AdminMessageService;
import com.kakarote.core.feign.admin.service.AdminService;
import com.kakarote.core.feign.examine.entity.ExamineDataSaveBO;
import com.kakarote.core.feign.examine.entity.ExamineFlowFinalUser;
import com.kakarote.core.feign.examine.entity.ExamineFlowVO;
import com.kakarote.core.servlet.ApplicationContextHolder;
import com.kakarote.core.servlet.BaseServiceImpl;
import com.kakarote.core.utils.BaseUtil;
import com.kakarote.core.utils.UserUtil;
import com.kakarote.examine.constant.ExamineCodeEnum;
import com.kakarote.examine.constant.ExamineStatusEnum;
import com.kakarote.examine.constant.ExamineTypeEnum;
import com.kakarote.examine.entity.PO.*;
import com.kakarote.examine.mapper.ExamineFlowOptionalMapper;
import com.kakarote.examine.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 审批流程自选成员记录表 服务实现类
 * </p>
 *
 * @author zhangzhiwei
 * @since 2020-11-13
 */
@Service("optionalService")
public class ExamineFlowOptionalServiceImpl extends BaseServiceImpl<ExamineFlowOptionalMapper, ExamineFlowOptional> implements IExamineFlowOptionalService, ExamineTypeService {

    @Autowired
    private AdminService adminService;

    @Autowired
    private IExamineFlowFinalOptionalService examineFlowFinalOptionalService;

    @Autowired
    private IExamineFlowFinalService examineFlowFinalService;

    @Autowired
    private IExamineRecordLogService examineRecordLogService;

    @Autowired
    private IExamineRecordService examineRecordService;

    private static final int TWO = 2;
    private static final int THREE = 3;

    /**
     * 保存额外的审批流程data对象
     *
     * @param dataSaveBO data
     * @param flowId     审批流程ID
     */
    @Override
    public void saveExamineFlowData(ExamineDataSaveBO dataSaveBO, Long flowId, String batchId) {
        Integer rangeType = dataSaveBO.getRangeType();
        if (Objects.equals(rangeType, THREE)) {
            List<Long> roleIdList = dataSaveBO.getRoleIdList();
            if (ObjectUtil.isNotEmpty(roleIdList)) {
                List<UserInfo> userInfoList = adminService.queryUserInfoList().getData();
                boolean isNoUser = true;
                for (UserInfo userInfo : userInfoList) {
                    Collection<Long> intersection = CollectionUtil.intersection(roleIdList, userInfo.getRoles());
                    if (!intersection.isEmpty()) {
                        isNoUser = false;
                        break;
                    }
                }
                if (isNoUser) {
                    throw new CrmException(ExamineCodeEnum.EXAMINE_ROLE_NO_USER_ERROR);
                }
                ExamineFlowOptional examineFlowOptional = new ExamineFlowOptional();
                examineFlowOptional.setChooseType(dataSaveBO.getChooseType());
                examineFlowOptional.setFlowId(flowId);
                examineFlowOptional.setRoleId(CollectionUtil.join(dataSaveBO.getRoleIdList(), ","));
                examineFlowOptional.setSort(1);
                examineFlowOptional.setType(dataSaveBO.getType());
                examineFlowOptional.setRangeType(dataSaveBO.getRangeType());
                examineFlowOptional.setBatchId(batchId);
                save(examineFlowOptional);
            }
        } else if (Objects.equals(rangeType, TWO)) {
            if (dataSaveBO.getUserList().size() == 0) {
                throw new CrmException(SystemCodeEnum.SYSTEM_NO_VALID);
            }
            for (Long userId : dataSaveBO.getUserList()) {
                ExamineFlowOptional examineFlowOptional = new ExamineFlowOptional();
                examineFlowOptional.setChooseType(dataSaveBO.getChooseType());
                examineFlowOptional.setFlowId(flowId);
                examineFlowOptional.setUserId(userId);
                examineFlowOptional.setSort(1);
                examineFlowOptional.setType(dataSaveBO.getType());
                examineFlowOptional.setRangeType(dataSaveBO.getRangeType());
                examineFlowOptional.setBatchId(batchId);
                save(examineFlowOptional);
            }
        } else {
            //全公司
            ExamineFlowOptional examineFlowOptional = new ExamineFlowOptional();
            examineFlowOptional.setChooseType(dataSaveBO.getChooseType());
            examineFlowOptional.setFlowId(flowId);
            examineFlowOptional.setSort(1);
            examineFlowOptional.setType(dataSaveBO.getType());
            examineFlowOptional.setRangeType(dataSaveBO.getRangeType());
            examineFlowOptional.setBatchId(batchId);
            save(examineFlowOptional);
        }

    }


    /**
     * 通过batchId查询所有flow关联对象
     *
     * @param map     缓存对象
     * @param batchId batchId
     */
    @Override
    public void queryFlowListByBatchId(Map<String, Object> map, String batchId) {
        List<ExamineFlowOptional> continuousSuperiors = lambdaQuery().eq(ExamineFlowOptional::getBatchId, batchId).list();
        Map<Long, List<ExamineFlowOptional>> collect = continuousSuperiors.stream().collect(Collectors.groupingBy(ExamineFlowOptional::getFlowId));
        map.put(ExamineTypeEnum.OPTIONAL.getServerName(), collect);
    }

    /**
     * 查询详情页需要的审批详情
     *
     * @param examineFlow 当前审批流程
     * @param map         缓存的map
     * @return data
     */
    @Override
    @SuppressWarnings("unchecked")
    public ExamineFlowVO createFlowInfo(ExamineFlow examineFlow, Map<String, Object> map, List<UserInfo> userInfoList, Long ownerUserId) {
        Map<Long, List<ExamineFlowOptional>> collect = (Map<Long, List<ExamineFlowOptional>>) map.get(ExamineTypeEnum.OPTIONAL.getServerName());
        List<ExamineFlowOptional> flowOptionals = collect.get(examineFlow.getFlowId());
        if (flowOptionals == null || flowOptionals.size() == 0) {
            return null;
        }
        ExamineFlowVO examineFlowVO = new ExamineFlowVO();
        examineFlowVO.setChooseType(flowOptionals.get(0).getChooseType());
        examineFlowVO.setName(examineFlow.getName());
        examineFlowVO.setExamineType(examineFlow.getExamineType());
        examineFlowVO.setFlowId(examineFlow.getFlowId());
        examineFlowVO.setType(flowOptionals.get(0).getType());
        examineFlowVO.setRangeType(flowOptionals.get(0).getRangeType());
        examineFlowVO.setExamineErrorHandling(examineFlow.getExamineErrorHandling());
        examineFlowVO.setRoleId(flowOptionals.get(0).getRoleId());
        List<SimpleUser> userList = new ArrayList<>();
        Integer rangeType = flowOptionals.get(0).getRangeType();
        if (Objects.equals(rangeType, THREE)) {
            //按照角色选择
            String roleId = flowOptionals.get(0).getRoleId();
            if (StrUtil.isNotEmpty(roleId)) {
                List<Long> roleIds = StrUtil.split(roleId, ',', -1, true, Long::valueOf);
                examineFlowVO.setRoleIdList(roleIds);
                for (UserInfo userInfo : userInfoList) {
                    Collection<Long> intersection = CollectionUtil.intersection(roleIds, userInfo.getRoles());
                    if (!intersection.isEmpty()) {
                        userList.add(toSimPleUser(userInfo));
                    }
                }
            }
        } else if (Objects.equals(rangeType, TWO)) {
            for (ExamineFlowOptional flowOptional : flowOptionals) {
                for (UserInfo userInfo : userInfoList) {
                    if (Objects.equals(flowOptional.getUserId(), userInfo.getUserId())) {
                        userList.add(toSimPleUser(userInfo));
                        break;
                    }
                }
            }
        }
        examineFlowVO.setUserList(userList);
        return examineFlowVO;
    }

    /**
     * 处理当前节点
     *
     * @param examineFlow 当前处理节点
     * @param recordId    审核记录ID
     * @param data        特殊处理所需数据(具体看实现类)
     * @param examine     审核对象
     * @param init        是否初始化
     * @return data
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject disposeFlow(ExamineFlow examineFlow, Long recordId, Object data, Examine examine, boolean init) {
        //是否首次处理
        boolean isFirst = true;

        ExamineRecord examineRecord = examineRecordService.getById(recordId);
        //处理条件flow examineId为0
        examineFlow.setExamineId(examineRecord.getExamineId());

        List<ExamineFlowOptional> list = lambdaQuery().eq(ExamineFlowOptional::getFlowId, examineFlow.getFlowId()).orderByAsc(ExamineFlowOptional::getSort).list();

        ExamineFlowOptional examineFlowOptional = list.get(0);

        ExamineFlowFinal examineFlowFinal = examineFlowFinalService.lambdaQuery().eq(ExamineFlowFinal::getRecordId, recordId)
                .eq(ExamineFlowFinal::getFlowId, examineFlow.getFlowId())
                .eq(ExamineFlowFinal::getExamineId, examineFlow.getExamineId()).one();

        if (examineFlowFinal == null) {
            Integer maxSort = examineFlowFinalService.getMaxSort(recordId, examineRecord.getExamineId());

            examineFlowFinal = new ExamineFlowFinal();
            examineFlowFinal.setName(examineFlow.getName());
            examineFlowFinal.setExamineType(examineFlow.getExamineType());
            examineFlowFinal.setFlowId(examineFlow.getFlowId());
            examineFlowFinal.setExamineErrorHandling(examineFlow.getExamineErrorHandling());
            examineFlowFinal.setCreateTime(new Date());
            examineFlowFinal.setCreateUserId(UserUtil.getUserId());
            examineFlowFinal.setExamineId(examineRecord.getExamineId());
            examineFlowFinal.setRecordId(recordId);
            examineFlowFinal.setType(examineFlowOptional.getType());
            examineFlowFinal.setSort(maxSort + 1);
            examineFlowFinalService.save(examineFlowFinal);
        } else {
            isFirst = false;
        }

        if (isFirst) {
            if (examine == null) {
                examine = ApplicationContextHolder.getBean(IExamineService.class).getById(examineRecord.getExamineId());
            }
            AdminMessageBO adminMessageBO = new AdminMessageBO();
            adminMessageBO.setUserId(UserUtil.getUserId());
            adminMessageBO.setMessageType(AdminMessageEnum.FLOW_OPTIONAL.getType());
            com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
            jsonObject.put("label", examineRecord.getLabel());
            jsonObject.put("typeId", examineRecord.getTypeId() + "");

            adminMessageBO.setContent(jsonObject.toJSONString());
            adminMessageBO.setTitle(examine.getExamineName());
            adminMessageBO.setTypeId(examineRecord.getTypeId());
            adminMessageBO.setIds(Collections.singletonList(examineRecord.getCreateUserId()));
            AdminMessageService messageService = ApplicationContextHolder.getBean(AdminMessageService.class);
            messageService.sendMessage(adminMessageBO);
            return new JSONObject().putOpt("status", ExamineStatusEnum.UNDERWAY.getStatus());
        }
        List<ExamineFlowFinalOptional> finalOptionals = new ArrayList<>();
        int index = 0;
        if (ObjectUtil.isNotEmpty(data)) {
            boolean exists = examineFlowFinalOptionalService.lambdaQuery()
                    .eq(ExamineFlowFinalOptional::getRecordId, recordId)
                    .eq(ExamineFlowFinalOptional::getFlowId, examineFlow.getFlowId()).exists();
            if (!exists) {
                for (ExamineFlowFinalUser datum : (List<ExamineFlowFinalUser>) data) {
                    ExamineFlowFinalOptional examineFlowFinalOptional = new ExamineFlowFinalOptional();
                    examineFlowFinalOptional.setCreateTime(new Date());
                    examineFlowFinalOptional.setCreateUserId(UserUtil.getUserId());
                    examineFlowFinalOptional.setFlowId(examineFlow.getFlowId());
                    examineFlowFinalOptional.setRecordId(recordId);
                    examineFlowFinalOptional.setType(1);
                    examineFlowFinalOptional.setSort(index++);
                    examineFlowFinalOptional.setUserId(datum.getUserId());
                    examineFlowFinalOptional.setEmail(datum.getEmail());
                    finalOptionals.add(examineFlowFinalOptional);
                }
            }
        }
        examineFlowFinalOptionalService.saveBatch(finalOptionals);

        if (finalOptionals.size() == 0) {
            //处理征求他人意见（）
            finalOptionals = examineFlowFinalOptionalService.lambdaQuery().eq(ExamineFlowFinalOptional::getRecordId, recordId)
                    .eq(ExamineFlowFinalOptional::getFlowId, examineFlow.getFlowId()).list();
        }

        String batchId = IdUtil.simpleUUID();
        LocalDateTime now = LocalDateTimeUtil.now();
        List<ExamineRecordLog> recordLogs = new ArrayList<>(finalOptionals.size());
        List<ExamineRecordLog> examineRecordLogList = examineRecordLogService.lambdaQuery().eq(ExamineRecordLog::getFlowId, examineFlowFinal.getFlowId())
                .ne(ExamineRecordLog::getExamineStatus, ExamineStatusEnum.CREATE.getStatus())
                .eq(ExamineRecordLog::getRecordId, examineFlowFinal.getRecordId()).list();
        List<ExamineRecordLog> updateRecordLogs = new ArrayList<>(examineRecordLogList.size());
        if (examineRecordLogList.size() == 0) {
            for (ExamineFlowFinalOptional examineFlowFinalUser : finalOptionals) {
                ExamineRecordLog examineRecordLog = new ExamineRecordLog();
                examineRecordLog.setLogId(BaseUtil.getNextId());
                examineRecordLog.setType(examineFlowFinal.getType());
                examineRecordLog.setCreateTime(now);
                examineRecordLog.setExamineTime(now);
                examineRecordLog.setUpdateTime(null);
                examineRecordLog.setCreateUserId(UserUtil.getUserId());
                examineRecordLog.setExamineUserEmail(examineFlowFinalUser.getEmail());
                examineRecordLog.setExamineId(examineFlowFinal.getExamineId());
                examineRecordLog.setExamineRoleId(0L);
                //   在这块判断审核人状态，是否有效等
                examineRecordLog.setExamineUserId(examineFlowFinalUser.getUserId());
                if (examineFlowFinal.getType() == 1) {
                    if (finalOptionals.indexOf(examineFlowFinalUser) == 0) {
                        examineRecordLog.setExamineStatus(ExamineStatusEnum.UNDERWAY.getStatus());
                    } else {
                        examineRecordLog.setExamineStatus(ExamineStatusEnum.AWAIT.getStatus());
                    }
                } else {
                    examineRecordLog.setExamineStatus(ExamineStatusEnum.UNDERWAY.getStatus());
                }
                if (ObjectUtil.isNotNull(examineFlowFinalUser.getUserId())) {
                    BaseUtil.getRedis().del(CrmCacheKey.CRM_BACKLOG_NUM_CACHE_KEY + examineFlowFinalUser.getUserId().toString());
                }
                examineRecordLog.setFlowId(examineFlowFinal.getFlowId());
                examineRecordLog.setRecordId(recordId);
                examineRecordLog.setSort(examineFlowFinalUser.getSort());
                examineRecordLog.setBatchId(batchId);
                recordLogs.add(examineRecordLog);
            }
            examineRecordLogService.saveBatch(recordLogs);
        } else {
            for (ExamineRecordLog recordLog : examineRecordLogList) {

                if (!recordLog.getExamineStatus().equals(ExamineStatusEnum.AWAIT.getStatus())) {
                    continue;
                }
                if (examineFlowFinal.getType() == 1) {
                    if (examineRecordLogList.indexOf(recordLog) == 0) {
                        recordLog.setExamineStatus(ExamineStatusEnum.UNDERWAY.getStatus());
                    } else {
                        recordLog.setExamineStatus(ExamineStatusEnum.AWAIT.getStatus());
                    }
                } else {
                    recordLog.setExamineStatus(ExamineStatusEnum.UNDERWAY.getStatus());
                }
                updateRecordLogs.add(recordLog);
            }
            if (updateRecordLogs.size() > 0) {
                examineRecordLogService.updateBatchById(updateRecordLogs);
            }
        }
        return ExamineTypeService.super.disposeFlow(examineFlow, recordId, data, examine, init);
    }


}
